home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '87 / Source ƒ.sea / Source ƒ / emacs source ƒ / RANDOM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-28  |  20.3 KB  |  741 lines  |  [TEXT/MARC]

  1. /*
  2.  * This file contains the command processing functions for a number of random
  3.  * commands. There is no functional grouping here, for sure.
  4.  */
  5.  
  6. #include        <stdio.h>
  7. #include    "estruct.h"
  8. #include        "edef.h"
  9.  
  10. int     tabsize;                        /* Tab size (0: use real tabs)  */
  11.  
  12. /*
  13.  * Set fill column to n.
  14.  */
  15. setfillcol(f, n)
  16. {
  17.         fillcol = n;
  18.     mlwrite("[Fill column is %d]",n);
  19.         return(TRUE);
  20. }
  21.  
  22. /*
  23.  * Display the current position of the cursor, in origin 1 X-Y coordinates,
  24.  * the character that is under the cursor (in hex), and the fraction of the
  25.  * text that is before the cursor. The displayed column is not the current
  26.  * column, but the column that would be used on an infinite width display.
  27.  * Normally this is bound to "C-X =".
  28.  */
  29. showcpos(f, n)
  30. {
  31.         register LINE   *lp;        /* current line */
  32.         register long   numchars;    /* # of chars in file */
  33.         register int    numlines;    /* # of lines in file */
  34.         register long   predchars;    /* # chars preceding point */
  35.         register int    predlines;    /* # lines preceding point */
  36.         register int    curchar;    /* character under cursor */
  37.         int ratio;
  38.         int col;
  39.     int savepos;            /* temp save for current offset */
  40.     int ecol;            /* column pos/end of current line */
  41.  
  42.     /* starting at the beginning of the buffer */
  43.         lp = lforw(curbp->b_linep);
  44.  
  45.     /* start counting chars and lines */
  46.         numchars = 0;
  47.         numlines = 0;
  48.         while (lp != curbp->b_linep) {
  49.         /* if we are on the current line, record it */
  50.         if (lp == curwp->w_dotp) {
  51.             predlines = numlines;
  52.             predchars = numchars + curwp->w_doto;
  53.             if ((curwp->w_doto) == llength(lp))
  54.                 curchar = '\n';
  55.             else
  56.                 curchar = lgetc(lp, curwp->w_doto);
  57.         }
  58.         /* on to the next line */
  59.         ++numlines;
  60.         numchars += llength(lp) + 1;
  61.         lp = lforw(lp);
  62.         }
  63.  
  64.     /* if at end of file, record it */
  65.     if (curwp->w_dotp == curbp->b_linep) {
  66.         predlines = numlines;
  67.         predchars = numchars;
  68.     }
  69.  
  70.     /* Get real column and end-of-line column. */
  71.     col = getccol(FALSE);
  72.     savepos = curwp->w_doto;
  73.     curwp->w_doto = llength(curwp->w_dotp);
  74.     ecol = getccol(FALSE);
  75.     curwp->w_doto = savepos;
  76.  
  77.         ratio = 0;              /* Ratio before dot. */
  78.         if (numchars != 0)
  79.                 ratio = (100L*predchars) / numchars;
  80.  
  81.     /* summarize and report the info */
  82.     mlwrite("Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x",
  83.         predlines+1, numlines+1, col, ecol,
  84.         predchars, numchars, ratio, curchar);
  85.         return (TRUE);
  86. }
  87.  
  88. /*
  89.  * Return current column.  Stop at first non-blank given TRUE argument.
  90.  */
  91. getccol(bflg)
  92. int bflg;
  93. {
  94.         register int c, i, col;
  95.         col = 0;
  96.         for (i=0; i<curwp->w_doto; ++i) {
  97.                 c = lgetc(curwp->w_dotp, i);
  98.                 if (c!=' ' && c!='\t' && bflg)
  99.                         break;
  100.                 if (c == '\t')
  101.                         col |= 0x07;
  102.                 else if (c<0x20 || c==0x7F)
  103.                         ++col;
  104.                 ++col;
  105.         }
  106.         return(col);
  107. }
  108.  
  109. /*
  110.  * Twiddle the two characters on either side of dot. If dot is at the end of
  111.  * the line twiddle the two characters before it. Return with an error if dot
  112.  * is at the beginning of line; it seems to be a bit pointless to make this
  113.  * work. This fixes up a very common typo with a single stroke. Normally bound
  114.  * to "C-T". This always works within a line, so "WFEDIT" is good enough.
  115.  */
  116. twiddle(f, n)
  117. {
  118.         register LINE   *dotp;
  119.         register int    doto;
  120.         register int    cl;
  121.         register int    cr;
  122.  
  123.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  124.         return(rdonly());    /* we are in read only mode    */
  125.         dotp = curwp->w_dotp;
  126.         doto = curwp->w_doto;
  127.         if (doto==llength(dotp) && --doto<0)
  128.                 return (FALSE);
  129.         cr = lgetc(dotp, doto);
  130.         if (--doto < 0)
  131.                 return (FALSE);
  132.         cl = lgetc(dotp, doto);
  133.         lputc(dotp, doto+0, cr);
  134.         lputc(dotp, doto+1, cl);
  135.         lchange(WFEDIT);
  136.         return (TRUE);
  137. }
  138.  
  139. /*
  140.  * Quote the next character, and insert it into the buffer. All the characters
  141.  * are taken literally, with the exception of the newline, which always has
  142.  * its line splitting meaning. The character is always read, even if it is
  143.  * inserted 0 times, for regularity. Bound to "C-Q"
  144.  */
  145. quote(f, n)
  146. {
  147.         register int    s;
  148.         register int    c;
  149.  
  150.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  151.         return(rdonly());    /* we are in read only mode    */
  152.         c = (*term.t_getchar)();
  153.         if (n < 0)
  154.                 return (FALSE);
  155.         if (n == 0)
  156.                 return (TRUE);
  157.         if (c == '\n') {
  158.                 do {
  159.                         s = lnewline();
  160.                 } while (s==TRUE && --n);
  161.                 return (s);
  162.         }
  163.         return (linsert(n, c));
  164. }
  165.  
  166. /*
  167.  * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
  168.  * tab into file.  If given argument, n, of zero, change to true tabs.
  169.  * If n > 1, simulate tab stop every n-characters using spaces. This has to be
  170.  * done in this slightly funny way because the tab (in ASCII) has been turned
  171.  * into "C-I" (in 10 bit code) already. Bound to "C-I".
  172.  */
  173. tab(f, n)
  174. {
  175.         if (n < 0)
  176.                 return (FALSE);
  177.         if (n == 0 || n > 1) {
  178.                 tabsize = n;
  179.                 return(TRUE);
  180.         }
  181.         if (! tabsize)
  182.                 return(linsert(1, '\t'));
  183.         return(linsert(tabsize - (getccol(FALSE) % tabsize), ' '));
  184. }
  185.  
  186. /*
  187.  * Open up some blank space. The basic plan is to insert a bunch of newlines,
  188.  * and then back up over them. Everything is done by the subcommand
  189.  * procerssors. They even handle the looping. Normally this is bound to "C-O".
  190.  */
  191. openline(f, n)
  192. {
  193.         register int    i;
  194.         register int    s;
  195.  
  196.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  197.         return(rdonly());    /* we are in read only mode    */
  198.         if (n < 0)
  199.                 return (FALSE);
  200.         if (n == 0)
  201.                 return (TRUE);
  202.         i = n;                                  /* Insert newlines.     */
  203.         do {
  204.                 s = lnewline();
  205.         } while (s==TRUE && --i);
  206.         if (s == TRUE)                          /* Then back up overtop */
  207.                 s = backchar(f, n);             /* of them all.         */
  208.         return (s);
  209. }
  210.  
  211. /*
  212.  * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
  213.  * indentation as specified.
  214.  */
  215. newline(f, n)
  216. {
  217.     register int    s;
  218.  
  219.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  220.         return(rdonly());    /* we are in read only mode    */
  221.     if (n < 0)
  222.         return (FALSE);
  223.  
  224.     /* if we are in C mode and this is a default <NL> */
  225.     if (n == 1 && (curbp->b_mode & MDCMOD) &&
  226.         curwp->w_dotp != curbp->b_linep)
  227.         return(cinsert());
  228.  
  229.     /* insert some lines */
  230.     while (n--) {
  231.         if ((s=lnewline()) != TRUE)
  232.             return (s);
  233.     }
  234.     return (TRUE);
  235. }
  236.  
  237. cinsert()    /* insert a newline and indentation for C */
  238.  
  239. {
  240.     register char *cptr;    /* string pointer into text to copy */
  241.     register int tptr;    /* index to scan into line */
  242.     register int bracef;    /* was there a brace at the end of line? */
  243.     register int i;
  244.     char ichar[NSTRING];    /* buffer to hold indent of last line */
  245.  
  246.     /* grab a pointer to text to copy indentation from */
  247.     cptr = &curwp->w_dotp->l_text[0];
  248.  
  249.     /* check for a brace */
  250.     tptr = curwp->w_doto - 1;
  251.     bracef = (cptr[tptr] == '{');
  252.  
  253.     /* save the indent of the previous line */
  254.     i = 0;
  255.     while ((i < tptr) && (cptr[i] == ' ' || cptr[i] == '\t')
  256.         && (i < NSTRING - 1)) {
  257.         ichar[i] = cptr[i];
  258.         ++i;
  259.     }
  260.     ichar[i] = 0;        /* terminate it */
  261.  
  262.     /* put in the newline */
  263.     if (lnewline() == FALSE)
  264.         return(FALSE);
  265.  
  266.     /* and the saved indentation */
  267.     i = 0;
  268.     while (ichar[i])
  269.         linsert(1, ichar[i++]);
  270.  
  271.     /* and one more tab for a brace */
  272.     if (bracef)
  273.         tab(FALSE, 1);
  274.  
  275.     return(TRUE);
  276. }
  277.  
  278. insbrace(n, c)    /* insert a brace into the text here...we are in CMODE */
  279.  
  280. int n;    /* repeat count */
  281. int c;    /* brace to insert (always { for now) */
  282.  
  283. {
  284.     register int ch;    /* last character before input */
  285.     register int i;
  286.     register int target;    /* column brace should go after */
  287.  
  288.     /* if we are at the beginning of the line, no go */
  289.     if (curwp->w_doto == 0)
  290.         return(linsert(n,c));
  291.         
  292.     /* scan to see if all space before this is white space */
  293.     for (i = curwp->w_doto - 1; i >= 0; --i) {
  294.         ch = lgetc(curwp->w_dotp, i);
  295.         if (ch != ' ' && ch != '\t')
  296.             return(linsert(n, c));
  297.     }
  298.  
  299.     /* delete back first */
  300.     target = getccol(FALSE);    /* calc where we will delete to */
  301.     target -= 1;
  302.     target -= target % (tabsize == 0 ? 8 : tabsize);
  303.     while (getccol(FALSE) > target)
  304.         backdel(FALSE, 1);
  305.  
  306.     /* and insert the required brace(s) */
  307.     return(linsert(n, c));
  308. }
  309.  
  310. inspound()    /* insert a # into the text here...we are in CMODE */
  311.  
  312. {
  313.     register int ch;    /* last character before input */
  314.     register int i;
  315.  
  316.     /* if we are at the beginning of the line, no go */
  317.     if (curwp->w_doto == 0)
  318.         return(linsert(1,'#'));
  319.         
  320.     /* scan to see if all space before this is white space */
  321.     for (i = curwp->w_doto - 1; i >= 0; --i) {
  322.         ch = lgetc(curwp->w_dotp, i);
  323.         if (ch != ' ' && ch != '\t')
  324.             return(linsert(1, '#'));
  325.     }
  326.  
  327.     /* delete back first */
  328.     while (getccol(FALSE) >= 1)
  329.         backdel(FALSE, 1);
  330.  
  331.     /* and insert the required pound */
  332.     return(linsert(1, '#'));
  333. }
  334.  
  335. /*
  336.  * Delete blank lines around dot. What this command does depends if dot is
  337.  * sitting on a blank line. If dot is sitting on a blank line, this command
  338.  * deletes all the blank lines above and below the current line. If it is
  339.  * sitting on a non blank line then it deletes all of the blank lines after
  340.  * the line. Normally this command is bound to "C-X C-O". Any argument is
  341.  * ignored.
  342.  */
  343. deblank(f, n)
  344. {
  345.         register LINE   *lp1;
  346.         register LINE   *lp2;
  347.         long nld;
  348.  
  349.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  350.         return(rdonly());    /* we are in read only mode    */
  351.         lp1 = curwp->w_dotp;
  352.         while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
  353.                 lp1 = lp2;
  354.         lp2 = lp1;
  355.         nld = 0;
  356.         while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
  357.                 ++nld;
  358.         if (nld == 0)
  359.                 return (TRUE);
  360.         curwp->w_dotp = lforw(lp1);
  361.         curwp->w_doto = 0;
  362.         return (ldelete(nld, FALSE));
  363. }
  364.  
  365. /*
  366.  * Insert a newline, then enough tabs and spaces to duplicate the indentation
  367.  * of the previous line. Assumes tabs are every eight characters. Quite simple.
  368.  * Figure out the indentation of the current line. Insert a newline by calling
  369.  * the standard routine. Insert the indentation by inserting the right number
  370.  * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
  371.  * subcomands failed. Normally bound to "C-J".
  372.  */
  373. indent(f, n)
  374. {
  375.         register int    nicol;
  376.         register int    c;
  377.         register int    i;
  378.  
  379.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  380.         return(rdonly());    /* we are in read only mode    */
  381.         if (n < 0)
  382.                 return (FALSE);
  383.         while (n--) {
  384.                 nicol = 0;
  385.                 for (i=0; i<llength(curwp->w_dotp); ++i) {
  386.                         c = lgetc(curwp->w_dotp, i);
  387.                         if (c!=' ' && c!='\t')
  388.                                 break;
  389.                         if (c == '\t')
  390.                                 nicol |= 0x07;
  391.                         ++nicol;
  392.                 }
  393.                 if (lnewline() == FALSE
  394.                 || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
  395.                 || ((i=nicol%8)!=0 && linsert(i,  ' ')==FALSE))
  396.                         return (FALSE);
  397.         }
  398.         return (TRUE);
  399. }
  400.  
  401. /*
  402.  * Delete forward. This is real easy, because the basic delete routine does
  403.  * all of the work. Watches for negative arguments, and does the right thing.
  404.  * If any argument is present, it kills rather than deletes, to prevent loss
  405.  * of text if typed with a big argument. Normally bound to "C-D".
  406.  */
  407. forwdel(f, n)
  408. {
  409.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  410.         return(rdonly());    /* we are in read only mode    */
  411.         if (n < 0)
  412.                 return (backdel(f, -n));
  413.         if (f != FALSE) {                       /* Really a kill.       */
  414.                 if ((lastflag&CFKILL) == 0)
  415.                         kdelete();
  416.                 thisflag |= CFKILL;
  417.         }
  418.         return (ldelete((long)n, f));
  419. }
  420.  
  421. /*
  422.  * Delete backwards. This is quite easy too, because it's all done with other
  423.  * functions. Just move the cursor back, and delete forwards. Like delete
  424.  * forward, this actually does a kill if presented with an argument. Bound to
  425.  * both "RUBOUT" and "C-H".
  426.  */
  427. backdel(f, n)
  428. {
  429.         register int    s;
  430.  
  431.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  432.         return(rdonly());    /* we are in read only mode    */
  433.         if (n < 0)
  434.                 return (forwdel(f, -n));
  435.         if (f != FALSE) {                       /* Really a kill.       */
  436.                 if ((lastflag&CFKILL) == 0)
  437.                         kdelete();
  438.                 thisflag |= CFKILL;
  439.         }
  440.         if ((s=backchar(f, n)) == TRUE)
  441.                 s = ldelete((long)n, f);
  442.         return (s);
  443. }
  444.  
  445. /*
  446.  * Kill text. If called without an argument, it kills from dot to the end of
  447.  * the line, unless it is at the end of the line, when it kills the newline.
  448.  * If called with an argument of 0, it kills from the start of the line to dot.
  449.  * If called with a positive argument, it kills from dot forward over that
  450.  * number of newlines. If called with a negative argument it kills backwards
  451.  * that number of newlines. Normally bound to "C-K".
  452.  */
  453. killtext(f, n)
  454. {
  455.         register LINE   *nextp;
  456.         long chunk;
  457.  
  458.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  459.         return(rdonly());    /* we are in read only mode    */
  460.         if ((lastflag&CFKILL) == 0)             /* Clear kill buffer if */
  461.                 kdelete();                      /* last wasn't a kill.  */
  462.         thisflag |= CFKILL;
  463.         if (f == FALSE) {
  464.                 chunk = llength(curwp->w_dotp)-curwp->w_doto;
  465.                 if (chunk == 0)
  466.                         chunk = 1;
  467.         } else if (n == 0) {
  468.                 chunk = curwp->w_doto;
  469.                 curwp->w_doto = 0;
  470.         } else if (n > 0) {
  471.                 chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
  472.                 nextp = lforw(curwp->w_dotp);
  473.                 while (--n) {
  474.                         if (nextp == curbp->b_linep)
  475.                                 return (FALSE);
  476.                         chunk += llength(nextp)+1;
  477.                         nextp = lforw(nextp);
  478.                 }
  479.         } else {
  480.                 mlwrite("neg kill");
  481.                 return (FALSE);
  482.         }
  483.         return(ldelete(chunk, TRUE));
  484. }
  485.  
  486. setmode(f, n)    /* prompt and set an editor mode */
  487.  
  488. int f, n;    /* default and argument */
  489.  
  490. {
  491.     adjustmode(TRUE, FALSE);
  492. }
  493.  
  494. delmode(f, n)    /* prompt and delete an editor mode */
  495.  
  496. int f, n;    /* default and argument */
  497.  
  498. {
  499.     adjustmode(FALSE, FALSE);
  500. }
  501.  
  502. setgmode(f, n)    /* prompt and set a global editor mode */
  503.  
  504. int f, n;    /* default and argument */
  505.  
  506. {
  507.     adjustmode(TRUE, TRUE);
  508. }
  509.  
  510. delgmode(f, n)    /* prompt and delete a global editor mode */
  511.  
  512. int f, n;    /* default and argument */
  513.  
  514. {
  515.     adjustmode(FALSE, TRUE);
  516. }
  517.  
  518. adjustmode(kind, global)    /* change the editor mode status */
  519.  
  520. int kind;    /* true = set,        false = delete */
  521. int global;    /* true = global flag,    false = current buffer flag */
  522. {
  523.     register char *scan;        /* scanning pointer to convert prompt */
  524.     register int i;            /* loop index */
  525. #if    COLOR
  526.     register int uflag;        /* was modename uppercase?    */
  527. #endif
  528.     char prompt[50];    /* string to prompt user with */
  529.     char cbuf[NPAT];        /* buffer to recieve mode name into */
  530.  
  531.     /* build the proper prompt string */
  532.     if (global)
  533.         strcpy(prompt,"Global mode to ");
  534.     else
  535.         strcpy(prompt,"Mode to ");
  536.  
  537.     if (kind == TRUE)
  538.         strcat(prompt, "add: ");
  539.     else
  540.         strcat(prompt, "delete: ");
  541.  
  542.     /* prompt the user and get an answer */
  543.  
  544.     mlreply(prompt, cbuf, NPAT - 1);
  545.  
  546.     /* make it uppercase */
  547.  
  548.     scan = cbuf;
  549. #if    COLOR
  550.     uflag = (*scan >= 'A' && *scan <= 'Z');
  551. #endif
  552.     while (*scan != 0) {
  553.         if (*scan >= 'a' && *scan <= 'z')
  554.             *scan = *scan - 32;
  555.         scan++;
  556.     }
  557.  
  558.     /* test it first against the colors we know */
  559.     for (i=0; i<NCOLORS; i++) {
  560.         if (strcmp(cbuf, cname[i]) == 0) {
  561.             /* finding the match, we set the color */
  562. #if    COLOR
  563.             if (uflag)
  564.                 if (global)
  565.                     gfcolor = i;
  566.                 else
  567.                     curwp->w_fcolor = i;
  568.             else
  569.                 if (global)
  570.                     gbcolor = i;
  571.                 else
  572.                     curwp->w_bcolor = i;
  573.  
  574.             curwp->w_flag |= WFCOLR;
  575. #endif
  576.             mlerase();
  577.             return(TRUE);
  578.         }
  579.     }
  580.  
  581.     /* test it against the modes we know */
  582.  
  583.     for (i=0; i < NUMMODES; i++) {
  584.         if (strcmp(cbuf, modename[i]) == 0) {
  585.             /* finding a match, we process it */
  586.             if (kind == TRUE)
  587.                 if (global)
  588.                     gmode |= (1 << i);
  589.                 else
  590.                     curwp->w_bufp->b_mode |= (1 << i);
  591.             else
  592.                 if (global)
  593.                     gmode &= ~(1 << i);
  594.                 else
  595.                     curwp->w_bufp->b_mode &= ~(1 << i);
  596.             /* display new mode line */
  597.             if (global == 0)
  598.                 upmode();
  599.             mlerase();    /* erase the junk */
  600.             return(TRUE);
  601.         }
  602.     }
  603.  
  604.     mlwrite("No such mode!");
  605.     return(FALSE);
  606. }
  607.  
  608. /*    This function simply clears the message line,
  609.         mainly for macro usage            */
  610.  
  611. clrmes(f, n)
  612.  
  613. int f, n;    /* arguments ignored */
  614.  
  615. {
  616.     mlwrite("");
  617.     return(TRUE);
  618. }
  619.  
  620. /*    This function writes a string on the message line
  621.         mainly for macro usage            */
  622.  
  623. writemsg(f, n)
  624.  
  625. int f, n;    /* arguments ignored */
  626.  
  627. {
  628.     register char *sp;    /* pointer into buf to expand %s */
  629.     register char *np;    /* ptr into nbuf */
  630.     register int status;
  631.     char buf[NPAT];        /* buffer to recieve mode name into */
  632.     char nbuf[NPAT*2];    /* buffer to expand string into */
  633.  
  634.     if ((status = mlreply("Message to write: ", buf, NPAT - 1)) != TRUE)
  635.         return(status);
  636.  
  637.     /* expand all '%' to "%%" so mlwrite won't expect arguments */
  638.     sp = buf;
  639.     np = nbuf;
  640.     while (*sp) {
  641.         *np++ = *sp;
  642.         if (*sp++ == '%')
  643.             *np++ = '%';
  644.     }
  645.     *np = '\0';
  646.     mlwrite(nbuf);
  647.     return(TRUE);
  648. }
  649.  
  650. /*    Close fences are matched against their partners, and if
  651.     on screen the cursor briefly lights there        */
  652.  
  653. fmatch(ch)
  654.  
  655. char ch;    /* fence type to match against */
  656.  
  657. {
  658.     register LINE *oldlp;    /* original line pointer */
  659.     register int oldoff;    /* and offset */
  660.     register LINE *toplp;    /* top line in current window */
  661.     register int count;    /* current fence level count */
  662.     register char opench;    /* open fence */
  663.     register char c;    /* current character in scan */
  664.     register int i;
  665.  
  666.     /* first get the display update out there */
  667.     update(FALSE);
  668.  
  669.     /* save the original cursor position */
  670.     oldlp = curwp->w_dotp;
  671.     oldoff = curwp->w_doto;
  672.  
  673.     /* setup proper open fence for passed close fence */
  674.     if (ch == ')')
  675.         opench = '(';
  676.     else
  677.         opench = '{';
  678.  
  679.     /* find the top line and set up for scan */
  680.     toplp = curwp->w_linep->l_bp;
  681.     count = 1;
  682.     backchar(FALSE, 2);
  683.  
  684.     /* scan back until we find it, or reach past the top of the window */
  685.     while (count > 0 && curwp->w_dotp != toplp) {
  686.         c = lgetc(curwp->w_dotp, curwp->w_doto);
  687.         if (c == ch)
  688.             ++count;
  689.         if (c == opench)
  690.             --count;
  691.         backchar(FALSE, 1);
  692.         if (curwp->w_dotp == curwp->w_bufp->b_linep->l_fp &&
  693.             curwp->w_doto == 0)
  694.             break;
  695.     }
  696.  
  697.     /* if count is zero, we have a match, display the sucker */
  698.     /* there is a real machine dependant timing problem here we have
  699.        yet to solve......... */
  700.     if (count == 0) {
  701.         forwchar(FALSE, 1);
  702.         for (i = 0; i < term.t_pause; i++)
  703.             update(FALSE);
  704.     }
  705.  
  706.     /* restore the current position */
  707.     curwp->w_dotp = oldlp;
  708.     curwp->w_doto = oldoff;
  709.     return(TRUE);
  710. }
  711.  
  712. istring(f, n)    /* ask for and insert a string into the current
  713.            buffer at the current point */
  714.  
  715. int f, n;    /* ignored arguments */
  716.  
  717. {
  718.     register char *tp;    /* pointer into string to add */
  719.     register int status;    /* status return code */
  720.     char tstring[NPAT+1];    /* string to add */
  721.  
  722.     /* ask for string to insert */
  723.     status = mlreplyt("String to insert<META>: ", tstring, NPAT, metac);
  724.     if (status != TRUE)
  725.         return(status);
  726.  
  727.     /* insert it */
  728.     tp = &tstring[0];
  729.     while (*tp) {
  730.         if (*tp == 0x0a)
  731.             status = lnewline();
  732.         else
  733.             status = linsert(1, *tp);
  734.         ++tp;
  735.         if (status != TRUE)
  736.             return(status);
  737.     }
  738.     return(TRUE);
  739. }
  740.  
  741.